<?php
/**
 * Esta clase hace lo mismo que Ext_Queue_Server, la cuestion es que en vez de usar
 * la vieja clas Ext_Queue utiliza Zend_Queue y tampoco usa la misma estrategia.
 *
 * La idea es hacer un remote procedure call a traves de Zend_Queue.
 * Esta clase implementa un metodo diferente a Ext_Queue_Server, el activeMQ no se configura para
 * llamar a ningun controller, esta clase se debe utilizar en un cron-job que poolea el server
 *
 */

class Ext_Queue_RpcServer
{
    const MSGBATCH=5;
    protected $_queue;
    protected $_serverClass;
    protected $_className;

    public function __construct( $queue, $className = null, $argv = null )
    {
        $this->_queue = $queue;
        if (1 < func_num_args()) {
            $argv = func_get_args();
            array_shift($argv);
            call_user_func_array( array( $this, 'setClass' ), $argv );
        }
    }

    public function setClass( $className, $argv = null )
    {
        $this->_className = $className;
        if (1 < func_num_args()) {
            $argv = func_get_args();
            array_shift($argv);
            $reflectionObj = new ReflectionClass( $className );
            $this->_serverClass = $reflectionObj->newInstanceArgs( $argv );
        } else {
            $this->_serverClass = new $className();
        }
    }

    public function handleForever( $errorQueue = null, $infoQueue = null ) {
        while( $this->handleUntilEmpty( $errorQueue, $infoQueue ) );
    }

    public function handleUntilEmpty( $errorQueue = null, $infoQueue = null ) {
        while( true ) {
            $messages = $this->getMessages( 1 );
            if ( $messages->count() == 0 ) {
                break;
            }
            foreach ($messages as $i => $msg) {
                try {
                    $ret = $this->handle( $msg );
                    $this->deleteMessage( $msg );
                    if ( ! empty( $infoQueue ) ) {
                        $infoQueue->send( Zend_Debug::dump($msg, 'Message', false) );
                        $infoQueue->send( Zend_Debug::dump($ret, 'RetVal', false) );
                    }
                } catch ( Exception $e ) {
                    if ( ! empty( $errorQueue ) ) {
                        // @todo: Log something
                        $errorQueue->send( $msg );
                    }
                }
            }
        }
        return true;
    }


    public function getMessages( $bcant ) {
        return $this->_queue->receive( $bcant );
    }

    public function getMessage() {
        $messages = $this->getMessages( 1 );
        return $messages->current();
    }

    public function handle( $message )
    {
        $message = new Ext_Queue_ExecMessage( $message->body );
        $funcName = $message->getFunction();
        $arguments = $message->getArguments();
        if ( in_array( $funcName, get_class_methods( $this->_className ) ) ) {
            $ret = call_user_func_array( array( $this->_serverClass, $funcName ), $arguments );
        } else {
            throw new Exception( 'invalid method' );
        }
        return $ret;
    }

    public function deleteMessage( $message ) {
        $this->_queue->deleteMessage( $message );
    }

}
